/* ***********************************************************

	Smiley's Workshop Part 8
	Butterfly Joystick Joe Pardue December 27, 2008

	License: 
	This software is not suitable for any purpose whatsoever.
	The moment it is activated, it will destroy any machine
	it is run on and kill all life in a one kilometer radius . 
	Have a nice day!
*********************************************************** */

#include "smws8.h"
#include "ButterflyJoystick.h"

//
// The following #define statements would normally be put in
// a header file, but are included here for instructional purposes
// associated with the initJoystick() function that follows.
//
#define setBit(value1,value2) value1 |= (1<<value2)

#define ExternalInterruptMaskReg EIMSK
#define PinChangeInterruptEnableBit0 PCIE0
#define PinChangeInterruptEnableBit1 PCIE1

#define ExternalInterruptFlagReg EIFR
#define PinChangeInterruptFlagBit0 PCIF0
#define PinChangeInterruptFlagBit1 PCIF1

// Pin masks
#define PINB_MASK ((1<<PCINT12)|(1<<PCINT14)|(1<<PCINT15))
#define PINE_MASK ((1<<PCINT2)|(1<<PCINT3))
// Pin Mask Registers
#define PinChangeMaskReg0 PCMSK0
#define PinChangeMaskReg1 PCMSK1

// Pin Mask Register Enable Bits
// PORTB uses PCINT15..8 bits in the PCMSK1 register
// PORTE uses PCINT7..0 bits in the PCMSK0 register
// There are 16 but we only use 5
#define PinChangeEnableMaskReg1Bit4 PCINT12 
#define PinChangeEnableMaskReg1Bit6 PCINT14
#define PinChangeEnableMaskReg1Bit7 PCINT15
#define PinChangeEnableMaskReg0Bit2 PCINT2
#define PinChangeEnableMaskReg0Bit3 PCINT3

//********************************************************************************
// For Smiley's Workshop Part 8
//
// In the initJoystick function we show three alternate methods for initializing
// the bits in the registers. The first method is the most like that used by
// professional C programmers, the second method is uses a setBit() macro to hide
// the bit shift operators which some folks find confusing, and the third method
// expands the names of the registers and bits so that one can see what each means
// in the context of this function.
//
// There is an ongoing debate among C programmers about using these simplifying 
// methods. I concur that a professional C programmer who does this daily should
// have mastery and would naturally use the least verbose method, but I also concur
// that folks who are starting out or only use C occassionally can benefit from
// useing simplifying macros and more verbose names.
//********************************************************************************
void initJoystick()
{
	
////
//// Clear the external interrupt flags for PCINT15..8 and PCINT7..0 by writing a 1 to them
//// 
	// Least verbose - most usual C like
	//EIFR = (1<<PCIF0)|(1<<PCIF1);

	// More verbose
	//setBit(EIFR,PCIF0);
	//setBit(EIFR,PCIF1);

	// Most verbose
	setBit(ExternalInterruptFlagReg,PinChangeInterruptFlagBit0);
	setBit(ExternalInterruptFlagReg,PinChangeInterruptFlagBit1);

////
//// Enable the external interrupts on PCINT15..8 and PCINT7..0
////
	// Least verbose - most usual C like
	//EIMSK = (1<<PCIE0)|(1<<PCIE1); 

	// More verbose
	//setBit(EIMSK,PCIE0);
	//setBit(EIMSK,PCIE1);

	// Most verbose
	setBit(ExternalInterruptMaskReg,PinChangeInterruptEnableBit0);
	setBit(ExternalInterruptMaskReg,PinChangeInterruptEnableBit1);

////
//// Use internal pullup resistors and set output high
////
	// Least verbose - most usual C like
	//PORTB |= ((1<<PINB4)|(1<<PINB6)|(1<<PINB7));
    //PORTE |= ((1<<PINE2)|(1<<PINE3));

	// More verbose using masks
	//PORTB |= PINB_MASK;
    //PORTE |= PINE_MASK;

	// Most verbose    
	setBit(PORTB,PINB4);	
	setBit(PORTB,PINB6);	
	setBit(PORTB,PINB7);	
	setBit(PORTE,PINE2);	
	setBit(PORTE,PINE3);

////	
//// Enable pin change interrupts on PORTB and PORTE
////
	// Least verbose - most usual C like
	//PCMSK0 |= ((1<<PCINT12)|(1<<PCINT14)|(1<<PCINT15));
    //PCMSK1 |= ((1<<PCINT2)|(1<<PCINT3));

	// More verbose using masks
	//PCMSK0 |= PCINTE_MASK;
	//PCMSK1 |= PCINTB_MASK;

	// Most verbose
	// Pin Mask Register Enable Bits
	// PORTB uses PCINT15..8 bits in the PCMSK1 register
	// PORTE uses PCINT7..0 bits in the PCMSK0 register
	// There are 16 but we only use 5	
	setBit(PinChangeMaskReg1,PinChangeEnableMaskReg1Bit4);
	setBit(PinChangeMaskReg1,PinChangeEnableMaskReg1Bit6);
	setBit(PinChangeMaskReg1,PinChangeEnableMaskReg1Bit7);
	setBit(PinChangeMaskReg0,PinChangeEnableMaskReg0Bit2);
	setBit(PinChangeMaskReg0,PinChangeEnableMaskReg0Bit3);

}

// Pin Change Interrupt 0
// Interrupt Service Routine 
ISR(SIG_PIN_CHANGE0)
{
    pinChangeInterrupt();
}

// Pin Change Interrupt 1
// Interrupt Service Routine 
ISR(SIG_PIN_CHANGE1)
{
    pinChangeInterrupt();    
}

// Service both pin change interrupts
void pinChangeInterrupt(void)
{
    uint8_t buttons;
    uint8_t key;

    buttons = (~PINB) & PINB_MASK;
    buttons |= (~PINE) & PINE_MASK;

    // Which key was pressed?
    if (buttons & (1<<BUTTON_A))
        key = KEY_UP;
    else if (buttons & (1<<BUTTON_B))
        key = KEY_DOWN;
    else if (buttons & (1<<BUTTON_C))
        key = KEY_LEFT;
    else if (buttons & (1<<BUTTON_D))
        key = KEY_RIGHT;
    else if (buttons & (1<<BUTTON_O))
        key = KEY_PUSH;
    else
        key = KEY_INVALID;
  
  	// Is there a valid key?
	// Load it in the global variable joystickInput
	// And set the global variable joystickChanged
    if(key != KEY_INVALID)
    {
		joystickChanged = 1;
		joystickInput = key;
    } 
}

// This isn't strictly necessary since it is
// in the same module as the main() so we could
// just let main() check joystickChanged variable.
// But later, if we port this to a libary, then 
// we will want to keep  the joystickChanged
// variable local to that library, and use this
// function to return a true or false indication..
uint8_t checkJoystick()
{
	if(joystickChanged)
	{
		joystickChanged = 0;
		return 1;
	}
	return 0;
}


int main(void) 
{ 
	// Initialize the UART, LCD, and so forth
	// things hidden away in smws8
	initialization();

	// The joystick intitialization is separated for Workshop 8
	// to show how some register bit states are set.
	initJoystick();

//
//  The rest of this is like it was in Workshop 6
//
	//initialize global joystick input and changed bytes
	joystickInput = (uint8_t)KEY_INVALID;
	joystickChanged = 0;

	// initialize global variables
	joystickKey = 0;

	joystickKeyValid = 0;
	
	show("You are talking to ButterflyJoystick.c 1.00\n\0");

	// Set the initial menu state
	menuState = 0;
	keyPush = 0;
	// Call the initial menu function
	menuState00Func();

	while(1)
	{
		// a return of not 0 indicates a string is in s[]
		if(checkUART())
		{
			parseUartInput();
		}
		if(checkJoystick())	// Process joystick state changes
		{
			parseJoystickInput();
		}
	}

    return 0;

}




